package xj.toolkit.netty.transport.endpoint;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.commons.collections4.Closure;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jmx.export.MBeanExporter;

import com.google.common.base.Preconditions;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import xj.toolkit.netty.transport.Receiver;
import xj.toolkit.netty.transport.TransportUtils;

public abstract class AbstractEndpoint<I> implements MutableEndpoint<I> {

	private static final Logger logger = LoggerFactory.getLogger(AbstractEndpoint.class);

	protected Closure<I> messageClosure;
	protected Receiver<I> nextReceiver;

	protected MBeanExporter mbeanExporter = null;

	protected String objectNamePrefix;

	protected ObjectName objectName = null;

	protected Channel channel = null;

	/**
	 * @return the objectNamePrefix
	 */
	public String getObjectNamePrefix() {
		return objectNamePrefix;
	}

	/**
	 * @param objectNamePrefix
	 *            the objectNamePrefix to set
	 */
	public void setObjectNamePrefix(String objectNamePrefix) {
		this.objectNamePrefix = objectNamePrefix;
	}

	/**
	 * @return the mbeanExport
	 */
	public MBeanExporter getMbeanExporter() {
		return mbeanExporter;
	}

	/**
	 * @param mbeanExporter
	 *            the mbeanExport to set
	 */
	public void setMbeanExporter(MBeanExporter mbeanExporter) {
		this.mbeanExporter = mbeanExporter;
	}

	public void messageReceived(ChannelHandlerContext ctx, I msg) {
		TransportUtils.attachSender(msg, this);

		if (null != messageClosure) {
			this.messageClosure.execute(msg);
		}
		if (null != nextReceiver) {
			this.nextReceiver.messageReceived(ctx, msg);
		}
	}

	@Override
	public void setChannel(Channel channel) {
		Preconditions.checkArgument(channel != null);
		this.channel = channel;
		
		if (null != objectName && null != mbeanExporter) {
			mbeanExporter.unregisterManagedResource(objectName);
		}
		
		if (null != mbeanExporter) {
			String channelStr = channel.remoteAddress().toString().replace("/", StringUtils.EMPTY).replace(":", "-");
			try {
				objectName = new ObjectName(objectNamePrefix + ",channel=" + channelStr);
				mbeanExporter.registerManagedResource(this, objectName);
			} catch (MalformedObjectNameException e) {
				logger.error("setChannel:", e);
			} catch (NullPointerException e) {
				logger.error("setChannel:", e);
			}
		}

	}

	/**
	 * 
	 * @see com.skymobi.transport.Endpoint#stop()
	 */
	public void stop() {
		if (null != objectName && null != mbeanExporter) {
			mbeanExporter.unregisterManagedResource(objectName);
		}
	}

	public void setMessageClosure(Closure<I> closure) {
		this.messageClosure = closure;
	}

	@Override
	public boolean prepared() {
		return channel != null && channel.isActive();
	}

}
